﻿using UnityEngine;
using System.Collections;

class wsVector2<T>
{
	//! X coordinate of vector.
	T x;

	//! Y coordinate of vector.
	T y;

	//! Default constructor (null vector)
	//wsVector2() : x(0), y(0) { }
	//! Constructor with two different values
	public wsVector2(T x, T y) { this.x = x; this.y = y; }
	//! Constructor with the same value for both members
	public wsVector2(T n) : this(n, n) { }
	//! Copy constructor
	public wsVector2(wsVector2<T> other) : this(other.x, other.y) { }
/*
	//wsVector2(const Dimension2d<T>& other) : x(other.width), y(other.height) {}

	// operators

	wsVector2<T> operator-() const { return wsVector2<T>(-x, -y); }

	wsVector2<T>& operator=(const wsVector2<T>& other) { x = other.x; y = other.y; return *this; }

	wsVector2<T>& operator=(const Dimension2d<T>& other) { x = other.width; y = other.height; return *this; }

	wsVector2<T> operator+(const wsVector2<T>& other) const { return wsVector2<T>(x + other.x, y + other.y); }
	wsVector2<T> operator+(const Dimension2d<T>& other) const { return wsVector2<T>(x + other.width, y + other.height); }
	wsVector2<T>& operator+=(const wsVector2<T>& other) { x+=other.x; y+=other.y; return *this; }
	wsVector2<T> operator+(const T v) const { return wsVector2<T>(x + v, y + v); }
	wsVector2<T>& operator+=(const T v) { x+=v; y+=v; return *this; }
	wsVector2<T>& operator+=(const Dimension2d<T>& other) { x += other.width; y += other.height; return *this;  }

	wsVector2<T> operator-(const wsVector2<T>& other) const { return wsVector2<T>(x - other.x, y - other.y); }
	wsVector2<T> operator-(const Dimension2d<T>& other) const { return wsVector2<T>(x - other.width, y - other.height); }
	wsVector2<T>& operator-=(const wsVector2<T>& other) { x-=other.x; y-=other.y; return *this; }
	wsVector2<T> operator-(const T v) const { return wsVector2<T>(x - v, y - v); }
	wsVector2<T>& operator-=(const T v) { x-=v; y-=v; return *this; }
	wsVector2<T>& operator-=(const Dimension2d<T>& other) { x -= other.width; y -= other.height; return *this;  }

	wsVector2<T> operator*(const wsVector2<T>& other) const { return wsVector2<T>(x * other.x, y * other.y); }
	wsVector2<T>& operator*=(const wsVector2<T>& other) { x*=other.x; y*=other.y; return *this; }
	wsVector2<T> operator*(const T v) const { return wsVector2<T>(x * v, y * v); }
	wsVector2<T>& operator*=(const T v) { x*=v; y*=v; return *this; }

	wsVector2<T> operator/(const wsVector2<T>& other) const { return wsVector2<T>(x / other.x, y / other.y); }
	wsVector2<T>& operator/=(const wsVector2<T>& other) { x/=other.x; y/=other.y; return *this; }
	wsVector2<T> operator/(const T v) const { return wsVector2<T>(x / v, y / v); }
	wsVector2<T>& operator/=(const T v) { x/=v; y/=v; return *this; }

	T operator [] (int i) { return (i==0)?x:y; }

	//! sort in order X, Y. Equality with rounding tolerance.
	bool operator<=(const wsVector2<T>&other) const
	{
		return 	(x<other.x || WhiteSnake::equals(x, other.x)) ||
			(WhiteSnake::equals(x, other.x) && (y<other.y || WhiteSnake::equals(y, other.y)));
	}

	//! sort in order X, Y. Equality with rounding tolerance.
	bool operator>=(const wsVector2<T>&other) const
	{
		return 	(x>other.x || WhiteSnake::equals(x, other.x)) ||
			(WhiteSnake::equals(x, other.x) && (y>other.y || WhiteSnake::equals(y, other.y)));
	}

	//! sort in order X, Y. Difference must be above rounding tolerance.
	bool operator<(const wsVector2<T>&other) const
	{
		return 	(x<other.x && !WhiteSnake::equals(x, other.x)) ||
			(WhiteSnake::equals(x, other.x) && y<other.y && !WhiteSnake::equals(y, other.y));
	}

	//! sort in order X, Y. Difference must be above rounding tolerance.
	bool operator>(const wsVector2<T>&other) const
	{
		return 	(x>other.x && !WhiteSnake::equals(x, other.x)) ||
			(WhiteSnake::equals(x, other.x) && y>other.y && !WhiteSnake::equals(y, other.y));
	}

	bool operator==(const wsVector2<T>& other) const { return equals(other); }
	bool operator!=(const wsVector2<T>& other) const { return !equals(other); }

	// functions

	bool equals(const wsVector2<T>& other) const
	{
		return WhiteSnake::equals(x, other.x) && WhiteSnake::equals(y, other.y);
	}

	wsVector2<T>& set(T nx, T ny) {x=nx; y=ny; return *this; }
	wsVector2<T>& set(const wsVector2<T>& p) { x=p.x; y=p.y; return *this; }
	wsVector2<T>& setAsVelocity(T speed, T degrees)
	{
		x = speed * cos_( degrees );
		y = speed * sin_( degrees ) * -1.0f;
	}

	// 벡터의 길이.
	T getLength() const { return WhiteSnake::squareroot( x*x + y*y ); }

	// 벡터의 길이의 제곱.
	T getLengthSQ() const { return x*x + y*y; }

	// 벡터의 내적.
	T dotProduct(const wsVector2<T>& other) const
	{
		return x*other.x + y*other.y;
	}

	// 두 점 사이의 거리.
	// 여기서 벡터는 2차원 공간에서의 점으로 해석한다.
	T getDistanceFrom(const wsVector2<T>& other) const
	{
		return wsVector2<T>(x - other.x, y - other.y).getLength();
	}

	// 두 점 사이의 거리의 제곱.
	// 여기서 벡터는 2차원 공간에서의 점으로 해석한다.
	T getDistanceFromSQ(const wsVector2<T>& other) const
	{
		return wsVector2<T>(x - other.x, y - other.y).getLengthSQ();
	}

	// center를 기준으로 degrees만큼 회전하기.
	wsVector2<T>& rotateBy(f64 degrees, const wsVector2<T>& center=wsVector2<T>())
	{
		degrees *= DEGTORAD64;
		const f64 cs = cos(degrees);
		const f64 sn = sin(degrees);

		x -= center.x;
		y -= center.y;

		set((T)(x*cs - y*sn), (T)(x*sn + y*cs));

		x += center.x;
		y += center.y;
		return *this;
	}

	// center를 기준으로 radians만큼 회전하기.
	wsVector2<T>& rotateByRadian(f64 radians, const wsVector2<T>& center=wsVector2<T>())
	{
		const f64 cs = WhiteSnake::cos64(radians);
		const f64 sn = WhiteSnake::sin64(radians);

		x -= center.x;
		y -= center.y;

		set((T)(x*cs - y*sn), (T)(x*sn + y*cs));

		x += center.x;
		y += center.y;
		return *this;
	}

	// this벡터를 정규화(길이를 1로 만들기)하기.
	// 길이가 0일경우에는 아무것도 하지 않는다.
	wsVector2<T>& normalize()
	{
		f32 length = (f32)(x*x + y*y);
		if (WhiteSnake::equals(length, 0.f))
			return *this;
		length = WhiteSnake::reciprocal_squareroot ( length );
		x = (t)(x * length);
		y = (t)(y * length);
		return *this;
	}

	// 삼각법에 의한 각도를 계산한다.
	// 각도는 3시방향을 0도로 간주하고 반시계방향으로 증가한다.
	// x : →, Y : ↑ 축을 기준으로 각도 구하기 (return : 0~360)
	f64 getAngleTrig() const
	{
		if (y == 0)
			return x < 0 ? 180 : 0;
		else
			if (x == 0)
				return y < 0 ? 270 : 90;

		if ( y > 0)
			if (x > 0)
				return atan(y/x) * RADTODEG64;
			else
				return 180.0-atan(y/-x) * RADTODEG64;
		else
			if (x > 0)
				return 360.0-atan(-y/x) * RADTODEG64;
			else
				return 180.0+atan(-y/-x) * RADTODEG64;
	}

	// 삼각법에 의한 각도를 계산한다.
	// 각도는 3시방향을 0도로 간주하고 시계방향으로 증가한다.
	// x : →, Y : ↓ 축을 기준으로 각도 구하기 (return : 0~360)
	inline f64 getAngle() const
	{
		if (y == 0) // corRected thanks to a suggestion by Jox
			return x < 0 ? 180 : 0;
		else if (x == 0)
			return y < 0 ? 90 : 270;

		// don't use getLength here to avoid precision loss with s32 vectors
		f64 tmp = y / sqrt((f64)(x*x + y*y));
		// 위의 코드를 이해해보자.
		// f64 tmp = y / sqrt((f64)(x*x + y*y));
		// 위에서 tmp는 Y/벡터의길이를 의미하게 된다. 
		// 벡터의 길이를 C라고 했을 때,	tmp = Y/C = sinθ
		tmp = atan( WhiteSnake::squareroot(1 - tmp*tmp) / tmp) * RADTODEG64;
		// 위의 코드역시 마저 풀이해보자.
		// 1 - tmp*tmp = 1-(y/C)^2 = (1-y/C)*(1+y/C) 이므로,
		// sqrt(1 - tmp*tmp) / tmp = sqrt((1-y/C)*(1+y/C)) * (C/y)
		// sqrt(C^2*(1-y/C)*(1+y/C)) / y = sqrt((C^2-CY)*(1+y/C)) / y
		// = sqrt(C^2 + CY - CY - y^2) / y = sqrt(C^2 - y^2) / y
		// 여기서 C^2 - Y^2는 피타고라스의 정리에 의해서 X^2이므로
		// sqrt(C^2 - y^2) / y = sqrt(x^2) / y = x / Y가 된다.
		// 결국, atan( WhiteSnake::squareroot(1 - tmp*tmp) / tmp) = atan(X/Y) 이고,
		// 이는 y축을 기준으로 한 각도를 구하게 된다.

		if (x>0 && y>0)
			return tmp + 270;
		else
			if (x>0 && y<0)
				return tmp + 90;
			else
				if (x<0 && y<0)
					return 90 - tmp;
				else
					if (x<0 && y>0)
						return 270 - tmp;

		return tmp;
	}

	// 두 벡터 사이의 각도 구하기 (return : 0~90)
	inline f64 getAngleWith(const wsVector2<T>& b) const
	{
		f64 tmp = x*b.x + y*b.y;

		if (tmp == 0.0)
			return 90.0;

		tmp = tmp / WhiteSnake::squareroot((f64)((x*x + y*y) * (b.x*b.x + b.y*b.y)));
		// 위의 코드를 이해해보자.
		// f64 tmp = x*b.x + y*b.y; 은 내적이므로 tmp = |A|*|B|*cosθ 이다.
		// squareroot((f64)((x*x + y*y) * (b.x*b.x + b.y*b.y))) 
		// = squareroot(|A|^2*|B|^2) = squareroot((|A|*|B|)^2) = |A|*|B| 이다.
		// 즉, tmp = tmp / WhiteSnake::squareroot((f64)((X*X + Y*Y) * (b.X*b.X + b.Y*b.Y)))
		// = (|A|*|B|*cosθ) / (|A|*|B|) = cosθ가 된다.

		if (tmp < 0.0)
			tmp = -tmp;

		return atan(sqrt(1 - tmp*tmp) / tmp) * RADTODEG64;
		// 위의 코드역시 마저 풀이해보자.
		// 1 - tmp*tmp = 1-(x/C)^2 = (1-x/C)*(1+x/C) 이므로,
		// sqrt(1 - tmp*tmp) / tmp = sqrt((1-x/C)*(1+x/C)) * (C/x)
		// sqrt(C^2*(1-x/C)*(1+x/C)) / x = sqrt((C^2-CX)*(1+x/C)) / x
		// = sqrt(C^2 + CX - CX - x^2) / x = sqrt(C^2 - x^2) / x
		// 여기서 C^2 - X^2는 피타고라스의 정리에 의해서 X^2이므로
		// sqrt(C^2 - x^2) / x = sqrt(y^2) / x = y / X가 된다.
		// 결국, atan( WhiteSnake::squareroot(1 - tmp*tmp) / tmp) = atan(Y/X) 이고,
		// 이는 x축을 기준으로 한 각도를 구하게 된다.
	}

	// this벡터를 직선위의 한 점으로 가정하고, 인자로 들어온 두 점이 직선(선분)의 시작점과 끝점일경우,
	// this벡터가 두 점 사이에 위치한다면 return true, 아니라면 return false.
	bool isBetweenPoints(const wsVector2<T>& begin, const wsVector2<T>& end) const
	{
		if (begin.x != end.x)
		{
			return ((begin.x <= x && x <= end.x) ||
				(begin.x >= x && x >= end.x));
		}
		else
		{
			return ((begin.y <= y && y <= end.y) ||
				(begin.y >= y && y >= end.y));
		}
	}

	// 보간 벡터 구하기.(getInterpolated_quadratic()와는 방향이 반대이다.)
	// d : 0.0f ~ 1.0f (0.0f -> other vector, 1.0f -> this vector.)
	wsVector2<T> getInterpolated(const wsVector2<T>& other, f64 d) const
	{
		f64 inv = 1.0f - d;
		return wsVector2<T>((T)(other.x*inv + x*d), (T)(other.y*inv + y*d));
	}

	// 2차보간 벡터 구하기.(getInterpolated()와는 방향이 반대이다.)
	// d : 0.0f ~ 1.0f (0.0f -> this vector, 0.5f -> v2 vector, 1.0f -> v3 vector.)
	wsVector2<T> getInterpolated_quadratic(const wsVector2<T>& v2, const wsVector2<T>& v3, f64 d) const
	{
		// this*(1-d)*(1-d) + 2 * v2 * (1-d) + v3 * d * d;
		const f64 inv = 1.0f - d;
		const f64 mul0 = inv * inv;
		const f64 mul1 = 2.0f * d * inv;
		const f64 mul2 = d * d;

		return wsVector2<T> ( (T)(x * mul0 + v2.x * mul1 + v3.x * mul2),
			(T)(y * mul0 + v2.y * mul1 + v3.y * mul2));
	}

	// this 벡터를 a와 b벡터사이의 선형보간 벡터로 만들기.
	// d : 0.0f ~ 1.0f (0.0f -> b vector, 1.0f -> a vector.)
	wsVector2<T>& interpolate(const wsVector2<T>& a, const wsVector2<T>& b, f64 d)
	{
		x = (T)((f64)b.x + ( ( a.x - b.x ) * d ));
		y = (T)((f64)b.y + ( ( a.y - b.y ) * d ));
		return *this;
	}
*/
};


/**********************************************************************************
 * ws_math_vector2d.h
 **********************************************************************************
#ifndef __WS_MATH_VECTOR_2D_H_INCLUDED__
#define __WS_MATH_VECTOR_2D_H_INCLUDED__

#include "ws_math.h"
#include "ws_math_dimension2d.h"

namespace WhiteSnake
{

	template <class T>
	class Vector2d
	{
	public:
		//! Default constructor (null vector)
		Vector2d() : x(0), y(0) {}
		//! Constructor with two different values
		Vector2d(T nx, T ny) : x(nx), y(ny) {}
		//! Constructor with the same value for both members
		explicit Vector2d(T n) : x(n), y(n) {}
		//! Copy constructor
		Vector2d(const Vector2d<T>& other) : x(other.x), y(other.y) {}

		Vector2d(const Dimension2d<T>& other) : x(other.width), y(other.height) {}

		// operators

		Vector2d<T> operator-() const { return Vector2d<T>(-x, -y); }

		Vector2d<T>& operator=(const Vector2d<T>& other) { x = other.x; y = other.y; return *this; }

		Vector2d<T>& operator=(const Dimension2d<T>& other) { x = other.width; y = other.height; return *this; }

		Vector2d<T> operator+(const Vector2d<T>& other) const { return Vector2d<T>(x + other.x, y + other.y); }
		Vector2d<T> operator+(const Dimension2d<T>& other) const { return Vector2d<T>(x + other.width, y + other.height); }
		Vector2d<T>& operator+=(const Vector2d<T>& other) { x+=other.x; y+=other.y; return *this; }
		Vector2d<T> operator+(const T v) const { return Vector2d<T>(x + v, y + v); }
		Vector2d<T>& operator+=(const T v) { x+=v; y+=v; return *this; }
		Vector2d<T>& operator+=(const Dimension2d<T>& other) { x += other.width; y += other.height; return *this;  }

		Vector2d<T> operator-(const Vector2d<T>& other) const { return Vector2d<T>(x - other.x, y - other.y); }
		Vector2d<T> operator-(const Dimension2d<T>& other) const { return Vector2d<T>(x - other.width, y - other.height); }
		Vector2d<T>& operator-=(const Vector2d<T>& other) { x-=other.x; y-=other.y; return *this; }
		Vector2d<T> operator-(const T v) const { return Vector2d<T>(x - v, y - v); }
		Vector2d<T>& operator-=(const T v) { x-=v; y-=v; return *this; }
		Vector2d<T>& operator-=(const Dimension2d<T>& other) { x -= other.width; y -= other.height; return *this;  }

		Vector2d<T> operator*(const Vector2d<T>& other) const { return Vector2d<T>(x * other.x, y * other.y); }
		Vector2d<T>& operator*=(const Vector2d<T>& other) { x*=other.x; y*=other.y; return *this; }
		Vector2d<T> operator*(const T v) const { return Vector2d<T>(x * v, y * v); }
		Vector2d<T>& operator*=(const T v) { x*=v; y*=v; return *this; }

		Vector2d<T> operator/(const Vector2d<T>& other) const { return Vector2d<T>(x / other.x, y / other.y); }
		Vector2d<T>& operator/=(const Vector2d<T>& other) { x/=other.x; y/=other.y; return *this; }
		Vector2d<T> operator/(const T v) const { return Vector2d<T>(x / v, y / v); }
		Vector2d<T>& operator/=(const T v) { x/=v; y/=v; return *this; }

		T operator [] (int i) { return (i==0)?x:y; }

		//! sort in order X, Y. Equality with rounding tolerance.
		bool operator<=(const Vector2d<T>&other) const
		{
			return 	(x<other.x || WhiteSnake::equals(x, other.x)) ||
				(WhiteSnake::equals(x, other.x) && (y<other.y || WhiteSnake::equals(y, other.y)));
		}

		//! sort in order X, Y. Equality with rounding tolerance.
		bool operator>=(const Vector2d<T>&other) const
		{
			return 	(x>other.x || WhiteSnake::equals(x, other.x)) ||
				(WhiteSnake::equals(x, other.x) && (y>other.y || WhiteSnake::equals(y, other.y)));
		}

		//! sort in order X, Y. Difference must be above rounding tolerance.
		bool operator<(const Vector2d<T>&other) const
		{
			return 	(x<other.x && !WhiteSnake::equals(x, other.x)) ||
				(WhiteSnake::equals(x, other.x) && y<other.y && !WhiteSnake::equals(y, other.y));
		}

		//! sort in order X, Y. Difference must be above rounding tolerance.
		bool operator>(const Vector2d<T>&other) const
		{
			return 	(x>other.x && !WhiteSnake::equals(x, other.x)) ||
				(WhiteSnake::equals(x, other.x) && y>other.y && !WhiteSnake::equals(y, other.y));
		}

		bool operator==(const Vector2d<T>& other) const { return equals(other); }
		bool operator!=(const Vector2d<T>& other) const { return !equals(other); }

		// functions

		bool equals(const Vector2d<T>& other) const
		{
			return WhiteSnake::equals(x, other.x) && WhiteSnake::equals(y, other.y);
		}

		Vector2d<T>& set(T nx, T ny) {x=nx; y=ny; return *this; }
		Vector2d<T>& set(const Vector2d<T>& p) { x=p.x; y=p.y; return *this; }
		Vector2d<T>& setAsVelocity(T speed, T degrees)
		{
			x = speed * cos_( degrees );
			y = speed * sin_( degrees ) * -1.0f;
		}

		// 벡터의 길이.
		T getLength() const { return WhiteSnake::squareroot( x*x + y*y ); }

		// 벡터의 길이의 제곱.
		T getLengthSQ() const { return x*x + y*y; }

		// 벡터의 내적.
		T dotProduct(const Vector2d<T>& other) const
		{
			return x*other.x + y*other.y;
		}

		// 두 점 사이의 거리.
		// 여기서 벡터는 2차원 공간에서의 점으로 해석한다.
		T getDistanceFrom(const Vector2d<T>& other) const
		{
			return Vector2d<T>(x - other.x, y - other.y).getLength();
		}

		// 두 점 사이의 거리의 제곱.
		// 여기서 벡터는 2차원 공간에서의 점으로 해석한다.
		T getDistanceFromSQ(const Vector2d<T>& other) const
		{
			return Vector2d<T>(x - other.x, y - other.y).getLengthSQ();
		}

		// center를 기준으로 degrees만큼 회전하기.
		Vector2d<T>& rotateBy(f64 degrees, const Vector2d<T>& center=Vector2d<T>())
		{
			degrees *= DEGTORAD64;
			const f64 cs = cos(degrees);
			const f64 sn = sin(degrees);

			x -= center.x;
			y -= center.y;

			set((T)(x*cs - y*sn), (T)(x*sn + y*cs));

			x += center.x;
			y += center.y;
			return *this;
		}

		// center를 기준으로 radians만큼 회전하기.
		Vector2d<T>& rotateByRadian(f64 radians, const Vector2d<T>& center=Vector2d<T>())
		{
			const f64 cs = WhiteSnake::cos64(radians);
			const f64 sn = WhiteSnake::sin64(radians);

			x -= center.x;
			y -= center.y;

			set((T)(x*cs - y*sn), (T)(x*sn + y*cs));

			x += center.x;
			y += center.y;
			return *this;
		}

		// this벡터를 정규화(길이를 1로 만들기)하기.
		// 길이가 0일경우에는 아무것도 하지 않는다.
		Vector2d<T>& normalize()
		{
			f32 length = (f32)(x*x + y*y);
			if (WhiteSnake::equals(length, 0.f))
				return *this;
			length = WhiteSnake::reciprocal_squareroot ( length );
			x = (t)(x * length);
			y = (t)(y * length);
			return *this;
		}

		// 삼각법에 의한 각도를 계산한다.
		// 각도는 3시방향을 0도로 간주하고 반시계방향으로 증가한다.
		// x : →, Y : ↑ 축을 기준으로 각도 구하기 (return : 0~360)
		f64 getAngleTrig() const
		{
			if (y == 0)
				return x < 0 ? 180 : 0;
			else
				if (x == 0)
					return y < 0 ? 270 : 90;

			if ( y > 0)
				if (x > 0)
					return atan(y/x) * RADTODEG64;
				else
					return 180.0-atan(y/-x) * RADTODEG64;
			else
				if (x > 0)
					return 360.0-atan(-y/x) * RADTODEG64;
				else
					return 180.0+atan(-y/-x) * RADTODEG64;
		}

		// 삼각법에 의한 각도를 계산한다.
		// 각도는 3시방향을 0도로 간주하고 시계방향으로 증가한다.
		// x : →, Y : ↓ 축을 기준으로 각도 구하기 (return : 0~360)
		inline f64 getAngle() const
		{
			if (y == 0) // corRected thanks to a suggestion by Jox
				return x < 0 ? 180 : 0;
			else if (x == 0)
				return y < 0 ? 90 : 270;

			// don't use getLength here to avoid precision loss with s32 vectors
			f64 tmp = y / sqrt((f64)(x*x + y*y));
			// 위의 코드를 이해해보자.
			// f64 tmp = y / sqrt((f64)(x*x + y*y));
			// 위에서 tmp는 Y/벡터의길이를 의미하게 된다. 
			// 벡터의 길이를 C라고 했을 때,	tmp = Y/C = sinθ
			tmp = atan( WhiteSnake::squareroot(1 - tmp*tmp) / tmp) * RADTODEG64;
			// 위의 코드역시 마저 풀이해보자.
			// 1 - tmp*tmp = 1-(y/C)^2 = (1-y/C)*(1+y/C) 이므로,
			// sqrt(1 - tmp*tmp) / tmp = sqrt((1-y/C)*(1+y/C)) * (C/y)
			// sqrt(C^2*(1-y/C)*(1+y/C)) / y = sqrt((C^2-CY)*(1+y/C)) / y
			// = sqrt(C^2 + CY - CY - y^2) / y = sqrt(C^2 - y^2) / y
			// 여기서 C^2 - Y^2는 피타고라스의 정리에 의해서 X^2이므로
			// sqrt(C^2 - y^2) / y = sqrt(x^2) / y = x / Y가 된다.
			// 결국, atan( WhiteSnake::squareroot(1 - tmp*tmp) / tmp) = atan(X/Y) 이고,
			// 이는 y축을 기준으로 한 각도를 구하게 된다.

			if (x>0 && y>0)
				return tmp + 270;
			else
				if (x>0 && y<0)
					return tmp + 90;
				else
					if (x<0 && y<0)
						return 90 - tmp;
					else
						if (x<0 && y>0)
							return 270 - tmp;

			return tmp;
		}

		// 두 벡터 사이의 각도 구하기 (return : 0~90)
		inline f64 getAngleWith(const Vector2d<T>& b) const
		{
			f64 tmp = x*b.x + y*b.y;

			if (tmp == 0.0)
				return 90.0;

			tmp = tmp / WhiteSnake::squareroot((f64)((x*x + y*y) * (b.x*b.x + b.y*b.y)));
			// 위의 코드를 이해해보자.
			// f64 tmp = x*b.x + y*b.y; 은 내적이므로 tmp = |A|*|B|*cosθ 이다.
			// squareroot((f64)((x*x + y*y) * (b.x*b.x + b.y*b.y))) 
			// = squareroot(|A|^2*|B|^2) = squareroot((|A|*|B|)^2) = |A|*|B| 이다.
			// 즉, tmp = tmp / WhiteSnake::squareroot((f64)((X*X + Y*Y) * (b.X*b.X + b.Y*b.Y)))
			// = (|A|*|B|*cosθ) / (|A|*|B|) = cosθ가 된다.

			if (tmp < 0.0)
				tmp = -tmp;

			return atan(sqrt(1 - tmp*tmp) / tmp) * RADTODEG64;
			// 위의 코드역시 마저 풀이해보자.
			// 1 - tmp*tmp = 1-(x/C)^2 = (1-x/C)*(1+x/C) 이므로,
			// sqrt(1 - tmp*tmp) / tmp = sqrt((1-x/C)*(1+x/C)) * (C/x)
			// sqrt(C^2*(1-x/C)*(1+x/C)) / x = sqrt((C^2-CX)*(1+x/C)) / x
			// = sqrt(C^2 + CX - CX - x^2) / x = sqrt(C^2 - x^2) / x
			// 여기서 C^2 - X^2는 피타고라스의 정리에 의해서 X^2이므로
			// sqrt(C^2 - x^2) / x = sqrt(y^2) / x = y / X가 된다.
			// 결국, atan( WhiteSnake::squareroot(1 - tmp*tmp) / tmp) = atan(Y/X) 이고,
			// 이는 x축을 기준으로 한 각도를 구하게 된다.
		}

		// this벡터를 직선위의 한 점으로 가정하고, 인자로 들어온 두 점이 직선(선분)의 시작점과 끝점일경우,
		// this벡터가 두 점 사이에 위치한다면 return true, 아니라면 return false.
		bool isBetweenPoints(const Vector2d<T>& begin, const Vector2d<T>& end) const
		{
			if (begin.x != end.x)
			{
				return ((begin.x <= x && x <= end.x) ||
					(begin.x >= x && x >= end.x));
			}
			else
			{
				return ((begin.y <= y && y <= end.y) ||
					(begin.y >= y && y >= end.y));
			}
		}

		// 보간 벡터 구하기.(getInterpolated_quadratic()와는 방향이 반대이다.)
		// d : 0.0f ~ 1.0f (0.0f -> other vector, 1.0f -> this vector.)
		Vector2d<T> getInterpolated(const Vector2d<T>& other, f64 d) const
		{
			f64 inv = 1.0f - d;
			return Vector2d<T>((T)(other.x*inv + x*d), (T)(other.y*inv + y*d));
		}

		// 2차보간 벡터 구하기.(getInterpolated()와는 방향이 반대이다.)
		// d : 0.0f ~ 1.0f (0.0f -> this vector, 0.5f -> v2 vector, 1.0f -> v3 vector.)
		Vector2d<T> getInterpolated_quadratic(const Vector2d<T>& v2, const Vector2d<T>& v3, f64 d) const
		{
			// this*(1-d)*(1-d) + 2 * v2 * (1-d) + v3 * d * d;
			const f64 inv = 1.0f - d;
			const f64 mul0 = inv * inv;
			const f64 mul1 = 2.0f * d * inv;
			const f64 mul2 = d * d;

			return Vector2d<T> ( (T)(x * mul0 + v2.x * mul1 + v3.x * mul2),
				(T)(y * mul0 + v2.y * mul1 + v3.y * mul2));
		}

		// this 벡터를 a와 b벡터사이의 선형보간 벡터로 만들기.
		// d : 0.0f ~ 1.0f (0.0f -> b vector, 1.0f -> a vector.)
		Vector2d<T>& interpolate(const Vector2d<T>& a, const Vector2d<T>& b, f64 d)
		{
			x = (T)((f64)b.x + ( ( a.x - b.x ) * d ));
			y = (T)((f64)b.y + ( ( a.y - b.y ) * d ));
			return *this;
		}

		//! X coordinate of vector.
		T x;

		//! Y coordinate of vector.
		T y;
	};

	// 스칼라값이 벡터와의 곱셈에서 연산자의 왼쪽에 올수 있도록 재정의한다.
	template<class S, class T>
	Vector2d<T> operator*(const S scalar, const Vector2d<T>& vector) { return vector*scalar; }

	// These methods are declared in Dimension2d, but need definitions of Vector2d
	template<class T>
	Dimension2d<T>::Dimension2d(const Vector2d<T>& other) : width(other.x), height(other.y) { }

	template<class T>
	bool Dimension2d<T>::operator==(const Vector2d<T>& other) const { return width == other.x && height == other.y; }

	typedef Vector2d<f32> Vector2df;
	typedef Vector2d<s32> Vector2di;
	typedef Vector2d<f32> v2f;
	typedef Vector2d<s32> v2i;

} // end namespace WhiteSnake

#endif
* 
*/